﻿using System.Collections.Generic;
using Base.Runtime;
using Extension.Runtime;
using Logic;
using ResourceModule.Runtime;
using UnityEngine;

namespace UIModule
{
    public struct WindowOpenData
    {
        public string AssetPath;
        public bool IsOpen;
        public int Index;
    }
    
    public class UIStackLayer:XBehaviourObject
    {
        public const int PER_WINDOW_ORDER = 1000;
        public UILayerInfo LayerInfo { get; private set; }
        
        private LinkedList<WindowBase> _windows = new LinkedList<WindowBase>();
        
        private Dictionary<string, GameObject> _prefabs = new Dictionary<string, GameObject>();
        
        public UIStackLayer(string layerName,Canvas uiRoot)
        {
            LayerInfo = new UILayerInfo(layerName, uiRoot);
        }
        
        protected override void OnInit()
        {
       
        }

        protected override void OnUpdate()
        {
            var cur = _windows.First;
            while (cur!=null)
            {
                var next = cur.Next;
                if (cur.Value.Data.IsOpen)
                {
                    cur.Value.Update();
                }
                cur = next;
            }
        }
        
        public void OpenWindow<T>(string assetPath,object userData = null) where T : WindowBase,new()
        {
            if (IsInOpenTask(assetPath))
            {
                Debug.LogWarning($"{assetPath} is opening!");
                return;
            }
            else
            {
                EnableRaycast(false);
                WindowBase window = new T();
                window.Data.AssetPath = assetPath;
                window.Data.Index = _windows.Count;
                window.Data.IsOpen = false;
                window.Init(userData);
                window.Node = _windows.AddLast(window);
                GameManger.ResourcesLoader.LoadAssetAsync<GameObject>(assetPath,OnLoadWindowSuccess,OnLoadWindowFail);
            }
        }

        public void CloseTop()
        {
            var top = _windows.Last;
            while (top!=null)
            {
                if (top.Value.Data.IsOpen)
                {
                    CloseWindow(top.Value);
                    return;
                }
                top = top.Previous;
            }
        }
        
        public void CloseWindow(WindowBase window)
        {
            if (window.Node!=null)
            {
                var previous = window.Node.Previous;
                var next = window.Node.Next;
                _windows.Remove(window.Node);
                window.Close();
                Object.Destroy(window.WindowGameObject);
                GameManger.ResourcesLoader.UnLoadAsset(window.Data.AssetPath);
                window.Dispose();
                if (previous!=null && previous == _windows.Last)
                {
                    previous.Value.Reveal();
                }
                while (next!= null)
                {
                    next.Value.Data.Index--;
                    next.Value.SetDepth(next.Value.Data.Index * PER_WINDOW_ORDER);
                    next = next.Next;
                }
            }
        }
        
        private bool IsInOpenTask(string assetPath)
        {
            var node = _windows.Last;
            while (node!= null)
            {
                if (node.Value.Data.AssetPath == assetPath)
                {
                    return true;
                }
                node = node.Previous;
            }
            return false;
        }

        private void EnableRaycast(bool enable)
        {
            LayerInfo.Raycaster.enabled = enable;
        }

        private void OnLoadWindowSuccess(IAssetRequest request)
        {
            _prefabs[request.RelativePath] = request.Asset as GameObject;
            if (IsAllLoadingFinish())
            {
                var cur = _windows.First;
                while (cur!=null)
                {
                    var next = cur.Next;
                    OpenWindow(cur.Value);
                    cur = next;
                }
                EnableRaycast(true);
            }
        }

        private void OpenWindow(WindowBase window)
        {
            var prefab = _prefabs[window.Data.AssetPath];
            var instance = UnityEngine.Object.Instantiate(prefab,LayerInfo.CachedTransform);
            instance.name = window.GetType().Name;
            instance.gameObject.SetActive(false);
            instance.transform.SetSiblingIndex(window.Data.Index);
            instance.transform.Reset();
            window.InitComponent(this,instance);
            window.BeforeOpen();
            instance.gameObject.SetActive(true);
            window.Open();
            window.SetDepth(GetSortingOrder(window.Data.Index));
            if (window.Node.Previous!=null)
            {
                window.Node.Previous.Value.Cover();
            }
            window.Data.IsOpen = true;
        }

        private int GetSortingOrder(int index)
        {
            return PER_WINDOW_ORDER * index;
        }
        
        private bool IsAllLoadingFinish()
        {
            var node = _windows.Last;
            while (node!= null)
            {
                if (!node.Value.Data.IsOpen )
                {
                    if (!_prefabs.ContainsKey(node.Value.Data.AssetPath))
                    {
                        return false;
                    }
                }
                else
                {
                    break;
                }
                node = node.Previous;
            }
            return true;
        }
        
        private void OnLoadWindowFail(string path)
        {
            EnableRaycast(true);
        }

        private void RemoveAsset(string assetPath)
        {
            
        }
        
        protected override void OnDispose()
        {
            LayerInfo.Dispose();
            LayerInfo = null;
        }

    }
}